package com.gzyj.server.nettyserver.handler;

import com.gzyj.jtt808.utils.HexBytesUtil;

import com.gzyj.jtt808.v2013.IPackageDecodeAdapter;
import com.gzyj.jtt808.v2013.PackageDecodeAdapter;
import com.gzyj.jtt808.v2013.Package;
import com.gzyj.jtt808.v2019.PackageHeader;
import com.gzyj.server.config.LogConfig;
import com.gzyj.server.config.NettyConfig;
import com.gzyj.server.config.SessionCache;
import com.gzyj.server.utils.StackUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @author lhj
 */

@Service
@ChannelHandler.Sharable
public class Server808Byte2MsgInHandler extends ChannelInboundHandlerAdapter {

    @Autowired
    NettyConfig.NettyServerConfig nettyConfig;

    @Value("${redis.key.pack.split}")
    private String RedisKey_SplitPack;

    @Resource(name = "clusterRedisTemplate")
    private RedisTemplate<String, Object> clusterRedisTemplate;


    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        //计数器加1
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //计数器减1
        LogConfig.commondLog.info("断开客户端连接,客户端信息 : {}", ctx.channel().remoteAddress().toString());
        super.channelInactive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {


        ByteBuf byteBuf = (ByteBuf) msg;
        LogConfig.commondLog.info("开始解析消息");

        String hex = ByteBufUtil.hexDump(byteBuf);
        try {
            if (hex.startsWith("7e")) {
                String tt = hex.substring(hex.indexOf("7e") + 2, hex.lastIndexOf("7e"));

                ByteBuf in = HexBytesUtil.readZy(tt);//转义处理
                String zyStr = ByteBufUtil.hexDump(in);

                int startFlag = Byte.toUnsignedInt(in.readByte());
                PackageHeader packageHeader = null;
                try {
                    packageHeader = new PackageHeader();
                    packageHeader.decode(in);
                } catch (Exception e) {
                    LogConfig.commondErrorLog.error("808头部解析错误 \n {}", StackUtils.getStackInfo(e));
                }
                try {
                    Object basePack = null;
                    if (packageHeader != null && packageHeader.getMsgBodyProperty().isVersionFlag()) {
                        LogConfig.commondLog.info("808 2019版本");
                        SessionCache.storage.put(packageHeader.getTerminalPhoneNo(), ctx);
                        com.gzyj.jtt808.v2019.PackageDecodeAdapter packageDecodeAdapter = new com.gzyj.jtt808.v2019.IPackageDecodeAdapter();
                        basePack = packageDecodeAdapter.decode(byteBuf);

                        com.gzyj.jtt808.v2019.Package tmp = (com.gzyj.jtt808.v2019.Package) basePack;

                        if (tmp.getPackageHeader().getMsgBodyProperty().isSubcontract()) {
                            LogConfig.commondLog.info("有分包");
                            if (tmp.getPackageHeader().getPackageIndex() == 1) {

                                clusterRedisTemplate.delete(RedisKey_SplitPack + "2019:" + tmp.getPackageHeader().getTerminalPhoneNo() + ":" + tmp.getPackageHeader().getMsgId());
                                clusterRedisTemplate.opsForList().rightPush(RedisKey_SplitPack + "2019:" + tmp.getPackageHeader().getTerminalPhoneNo() + ":" + tmp.getPackageHeader().getMsgId(), hex);

                            } else if (tmp.getPackageHeader().getPackageIndex() == tmp.getPackageHeader().getPackgeCount()) {
                                List<Object> allStrs = clusterRedisTemplate.opsForList().range(RedisKey_SplitPack + "2019:" + tmp.getPackageHeader().getTerminalPhoneNo() + ":" + tmp.getPackageHeader().getMsgId(), 0, -1);

                                List<ByteBuf> byteBufs = new ArrayList<>();
                                for (Object obj : allStrs) {

                                    String hx = (String) obj;

                                    com.gzyj.jtt808.v2019.PackageDecodeAdapter adapter = new com.gzyj.jtt808.v2019.IPackageDecodeAdapter();
                                    com.gzyj.jtt808.v2019.Package hxp = adapter.decode(Unpooled.copiedBuffer(HexBytesUtil.hexTobytes(hx)));
                                    byteBufs.add(hxp.SubDataBodies);


                                }
                                byteBufs.add(tmp.SubDataBodies);
                                ByteBuf total = Unpooled.copiedBuffer(byteBufs.toArray(new ByteBuf[byteBufs.size()]));
                                tmp.setSubDataBodies(total);
                                basePack = tmp;


                                LogConfig.commondLog.info("分包大小 {}", allStrs.size());
                                if (basePack != null) {
                                    ctx.fireChannelRead(basePack);
                                }
                            } else {
                                clusterRedisTemplate.opsForList().rightPush(RedisKey_SplitPack + "2019:" + tmp.getPackageHeader().getTerminalPhoneNo() + ":" + tmp.getPackageHeader().getMsgId(), hex);
                            }


                        } else {
                            if (basePack != null) {
                                ctx.fireChannelRead(basePack);
                            }
                        }

                    } else if (packageHeader != null && !packageHeader.getMsgBodyProperty().isVersionFlag()) {
                        LogConfig.commondLog.info("808 2011或2013版本");

                        try {
                            PackageDecodeAdapter packageDecodeAdapter = new IPackageDecodeAdapter();
                            basePack = packageDecodeAdapter.decode(byteBuf);
                            SessionCache.storage.put(packageHeader.getTerminalPhoneNo(), ctx);

                            Package tmp = (Package) basePack;
                            if (tmp.getPackageHeader().getMsgBodyProperty().isSubcontract()) {
                                LogConfig.commondLog.info("有分包");
                                if (tmp.getPackageHeader().getPackageIndex() == 1) {
                                    clusterRedisTemplate.delete(RedisKey_SplitPack + "2013:" + tmp.getPackageHeader().getTerminalPhoneNo() + ":" + tmp.getPackageHeader().getMsgId());
                                    clusterRedisTemplate.opsForList().rightPush(RedisKey_SplitPack + "2013:" + tmp.getPackageHeader().getTerminalPhoneNo() + ":" + tmp.getPackageHeader().getMsgId(), hex);
                                } else if (tmp.getPackageHeader().getPackageIndex() == tmp.getPackageHeader().getPackgeCount()) {
                                    List<Object> allStrs = clusterRedisTemplate.opsForList().range(RedisKey_SplitPack + "2013:" + tmp.getPackageHeader().getTerminalPhoneNo() + ":" + tmp.getPackageHeader().getMsgId(), 0, -1);

                                    List<ByteBuf> byteBufs = new ArrayList<>();
                                    for (Object obj : allStrs) {

                                        String hx = (String) obj;

                                        PackageDecodeAdapter adapter = new IPackageDecodeAdapter();
                                        Package hxp = adapter.decode(Unpooled.copiedBuffer(HexBytesUtil.hexTobytes(hx)));
                                        byteBufs.add(hxp.SubDataBodies);


                                    }
                                    byteBufs.add(tmp.SubDataBodies);
                                    ByteBuf total = Unpooled.copiedBuffer(byteBufs.toArray(new ByteBuf[byteBufs.size()]));
                                    tmp.setSubDataBodies(total);
                                    basePack = tmp;


                                    LogConfig.commondLog.info("分包大小 {}", allStrs.size());
                                    if (basePack != null) {
                                        ctx.fireChannelRead(basePack);
                                    }
                                } else {


                                    clusterRedisTemplate.opsForList().rightPush(RedisKey_SplitPack + "2013:" + tmp.getPackageHeader().getTerminalPhoneNo() + ":" + tmp.getPackageHeader().getMsgId(), hex);
                                }


                            } else {
                                if (basePack != null) {
                                    ctx.fireChannelRead(basePack);
                                }
                            }


                            LogConfig.commondLog.info("808 2013版本");
                        } catch (Exception e) {
                            if (packageHeader.getMsgId() == 0x0100 || packageHeader.getMsgId() == 0x0801) {
                                com.gzyj.jtt808.v2011.PackageDecodeAdapter packageDecodeAdapter = new com.gzyj.jtt808.v2011.IPackageDecodeAdapter();
                                basePack = packageDecodeAdapter.decode(HexBytesUtil.readZy(tt));

                                SessionCache.storage.put(packageHeader.getTerminalPhoneNo(), ctx);

                                LogConfig.commondLog.info("808 2011版本");
                                if (basePack != null) {
                                    ctx.fireChannelRead(basePack);
                                }
                            } else {
                                LogConfig.commondErrorLog.error("808协议解析错误 {} \n {}", hex, StackUtils.getStackInfo(e));
                            }
                        }


                    }


                } catch (Exception e) {
                    LogConfig.commondErrorLog.error("808协议解析错误 {} \n {} ", hex, StackUtils.getStackInfo(e));
                    e.printStackTrace();
                }
            } else {
                ctx.fireChannelRead(byteBuf);
            }

        } catch (Exception e) {
            LogConfig.commondErrorLog.error("808协议解析错误 {} \n {}", hex, StackUtils.getStackInfo(e));
        }


    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.READER_IDLE) {
                LogConfig.commondLog.warn("客户端连接超时,客户端信息 : {}", ctx.channel().remoteAddress().toString());
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        super.channelWritabilityChanged(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        LogConfig.commondErrorLog.error("发生错误 \n {}", StackUtils.getStackInfo(cause));
        ctx.close();
    }

}
